﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using Microsoft.TeamFoundation;
using Microsoft.TeamFoundation.VersionControl.Client;

namespace TFhisto.UI
{
     //<summary>
     //Interaction logic for ChangesetHistory.xaml
     //</summary>
    public partial class ChangesetHistory: UserControl
    {
        #region Fields
        private List<BranchData> _branches = new List<BranchData>();

        private List<FileChangeInfo> _selectedFiles = new List<FileChangeInfo>();

        public List<FileChangeInfo> SelectedFiles
        {
            get { return _selectedFiles; }
            set
            {
                _selectedFiles = value;
                lstSelectedFiles.ItemsSource = _selectedFiles;
            }
        }

        public void AddSelectedFile(string localPath)
        {
            if (_selectedFiles.Count == 2 && _selectedFiles[0].ChangeType != null && _selectedFiles[0].ChangeType.Equals("INFO"))
            {
                _selectedFiles.RemoveAll(delegate(FileChangeInfo f) { return f.ChangeType.Equals("INFO"); });
                BtnAddItem.IsEnabled = true;
                BtnEditItem.IsEnabled = true;
                BtnRemoveItem.IsEnabled = true;
                BtnSelectItem.IsEnabled = true;
                BtnUnselectItem.IsEnabled = true;
            }
            
            lstSelectedFiles.ItemsSource = null;
            string serverPath = localPath;
            if (serverPath[0] != '$')
            {
                serverPath = CommonUIHelper.GetServerItemForLocalItem(localPath);
            }

            FileChangeInfo file = new FileChangeInfo();
            file.FullPath = serverPath;
            file.Checked = true;
            file.Selected = true;

            if (!_selectedFiles.Contains(file))
            {
                _selectedFiles.Add(file);
            }
            lstSelectedFiles.ItemsSource = _selectedFiles;
        }

        public void RemoveSelectedFile(string serverPath)
        {
            FileChangeInfo file = new FileChangeInfo();
            file.FullPath = serverPath;

            if (_selectedFiles.Contains(file))
            {
                _selectedFiles.Remove(file);
            }
            lstSelectedFiles.ItemsSource = null;
            lstSelectedFiles.ItemsSource = _selectedFiles;
        }

        public string SelectedTeamProjectCollectionName
        { get; set; }

        public string SelectedTeamProjectName
        { get; set; }
        #endregion

        #region Class Scoped Values
        /// <summary>
        /// Stores the selected link types
        /// </summary>
        private List<TempLinkType> _selectedLinks = null;

        /// <summary>
        /// Stores the branches that back the list view for
        /// processing
        /// </summary>
        private List<BranchData> _queryResults = null;

        private bool IsInSearchByFile = true;

        #endregion

        #region constructor
        public ChangesetHistory()
        {
            System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly();
            string codeBase = System.IO.Path.GetDirectoryName(assembly.CodeBase);
            CommonUIHelper.Helper.IconResourcePath = codeBase.Substring(6) + "\\Icons\\";
        
            InitializeComponent();
            CommonUIHelper.Helper.PropertyChanged += new PropertyChangedEventHandler(Helper_PropertyChanged);
            txtOutput.Text = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "\\Output.dgml";

            FileChangeInfo info = new FileChangeInfo();
            info.FullPath = "1. Open a solution under TFS Source control.";
            info.ChangeType = "INFO";
            info.Selected = false;
            _selectedFiles.Add(info);

            info = new FileChangeInfo();
            info.FullPath = "2. Send a file to TFS history from the Solution Explorer.";
            info.ChangeType = "INFO";
            info.Selected = false;
            _selectedFiles.Add(info);

            lstSelectedFiles.ItemsSource = _selectedFiles;
            rbSearchByFile.IsChecked = true;
        }
        #endregion

        #region Processing management
        private void Helper_PropertyChanged(Object sender, PropertyChangedEventArgs args)
        {
            if (args.PropertyName.Equals("StatusMessage"))
            {
                ((StatusBarItem)statusBar.Items[0]).Content = CommonUIHelper.Helper.StatusMessage;
            }
            else if (args.PropertyName.Equals("FilePath"))
            {
                AddSelectedFile(CommonUIHelper.Helper.FilePath);
            }
            else if (args.PropertyName.Equals("ModifyFilePath"))
            {
                RemoveSelectedFile(CommonUIHelper.Helper.OldFilePath);
                AddSelectedFile(CommonUIHelper.Helper.FilePath);
            }
        }
        #endregion

        #region Select a project and Load Treeview and List
        /// <summary>
        /// Populate the list of branches
        /// </summary>
        public void LoadProject()
        {
            if (string.IsNullOrEmpty(SelectedTeamProjectName))
            {
                MessageBox.Show("An error occurred when we tried to load your Team Project");
                return;
            }

            _queryResults = CommonUIHelper.GetBranches();
            LoadListView(_queryResults);

            _selectedLinks = CommonUIHelper.LoadLinkTypesForChangeset(SelectedTeamProjectName);
            lstChangeTypes.ItemsSource = _selectedLinks;
        }
        #endregion

        #region Run Query
        /// <summary>
        /// Loads the listview with branches returned by TFS SCM
        /// </summary>
        /// <param name="branches">The collection of branches</param>
        private void LoadListView(List<BranchData> branches)
        {
            //Set the data source of the grid to be the branches collection
            this._branches = branches;
            lstResults.ItemsSource = this._branches;

            //Clear the columns that are already in the grid
            GridView g = (GridView)lstResults.View;
            g.Columns.Clear();

            // Set the selection column
            System.Windows.Controls.GridViewColumn selection = new System.Windows.Controls.GridViewColumn();
            selection.CellTemplate = (DataTemplate)this.FindResource("SelectionColumn");
            selection.HeaderTemplate = (DataTemplate)this.FindResource("SelectionHeaderColumn");
            selection.Width = 38;
            g.Columns.Add(selection);

            // Set the column that show the branch path
            System.Windows.Controls.GridViewColumn path = new System.Windows.Controls.GridViewColumn();
            path.Header = "Path";
            path.DisplayMemberBinding = new Binding("Path") { Mode = BindingMode.OneTime };
            path.Width = lstResults.Width - 30;
            g.Columns.Add(path);
        }
        #endregion

        #region Button Clicks and Checkbox management
        /// <summary>
        /// Allows the user to select the output file for the generated DGML
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnBrowse_Click(object sender, RoutedEventArgs e)
        {
            txtOutput.Text = CommonUIHelper.SetOutputFileName("Output.dgml");
        }


        /// <summary>
        /// Create the work item graph in DGML
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnChangeset_Click(object sender, RoutedEventArgs e)
        {
            Mouse.OverrideCursor = Cursors.Wait;

            Dictionary<SearchCriteria, Object> searchCriterias = new Dictionary<SearchCriteria, object>();
            string groupByFieldName = ((System.Windows.Input.ICommandSource)sender).CommandParameter as string;
            CommonUIHelper.Reset();

            try
            {
                #region Input form validation
                if (IsInSearchByFile)
                {
                    if (_selectedFiles.FindAll(delegate(FileChangeInfo f) { return f.Selected; }).Count == 0)
                    {
                        MessageBox.Show("Add a File from the Solution Explorer, and select at least one file to proceed.");
                        return;
                    }
                }
                else
                {
                    int changesetID;
                    if (!int.TryParse(txbChangesetID.Text, out changesetID))
                    {
                        txbChangesetIDErrorMessage.Visibility = Visibility.Visible;
                        return;
                    }
                    else
                    {
                        try
                        {
                            txbChangesetIDErrorMessage.Visibility = Visibility.Hidden;
                            _selectedFiles = CommonUIHelper.GetFilesByChangesetID(changesetID);

                            if (_selectedFiles == null || _selectedFiles.Count == 0)
                            {
                                MessageBox.Show("Check the Changeset number you provide. No file has been found associated to this number.", "Invalid changeset number");
                                return;
                            }
                        }
                        catch (ChangesetNotFoundException ex)
                        {
                            MessageBox.Show(ex.Message, "Invalid changeset number");
                            return;
                        }
                    }
                }

                int changesetIdFrom, changesetIdTo = 0;
                DateTime dateFrom, dateTo;

                int.TryParse(filterChangesetFrom.Text, out changesetIdFrom);
                int.TryParse(filterChangesetTo.Text, out changesetIdTo);
                DateTime.TryParse(filterDateFrom.SelectedDate.ToString(), CultureInfo.CurrentCulture, DateTimeStyles.None, out dateFrom);
                DateTime.TryParse(filterDateTo.SelectedDate.ToString(), CultureInfo.CurrentCulture, DateTimeStyles.None, out dateTo);

                // We consider the label pattern
                string labelPattern = string.Empty;
                if (txbLabelPattern.IsEnabled && txbLabelPattern.Text.Length > 0)
                {
                    labelPattern = txbLabelPattern.Text;
                }
                // We consider ChangesetID filters
                if (changesetIdFrom > 0 && changesetIdTo > 0 && changesetIdFrom > changesetIdTo)
                {
                    filterErrorMessage.Content = "FROM Changeset ID must be lower than TO Changeset ID";
                    filterErrorMessage.Visibility = System.Windows.Visibility.Visible;
                    return;
                }
                if (changesetIdFrom > 0)
                {
                    searchCriterias.Add(SearchCriteria.ChangesetFrom, changesetIdFrom);
                }
                else if (filterChangesetFrom.Text.Length > 0 && !int.TryParse(filterChangesetFrom.Text, out changesetIdFrom))
                {
                    filterErrorMessage.Content = "Invalid FROM Changeset ID format";
                    filterErrorMessage.Visibility = System.Windows.Visibility.Visible;
                    return;
                }
                if (changesetIdTo > 0)
                {
                    searchCriterias.Add(SearchCriteria.ChangesetTo, changesetIdTo);
                }
                else if (filterChangesetTo.Text.Length > 0 && !int.TryParse(filterChangesetTo.Text, out changesetIdTo))
                {
                    filterErrorMessage.Content = "Invalid TO Changeset ID format";
                    filterErrorMessage.Visibility = System.Windows.Visibility.Visible;
                    return;
                }

                // We consider DatePickers filters
                if (dateFrom.CompareTo(dateTo) == 1 && dateTo != DateTime.MinValue)
                {
                    filterErrorMessage.Content = "AFTER Date must be lower than BEFORE Date";
                    filterErrorMessage.Visibility = System.Windows.Visibility.Visible;
                    return;
                }
                if (dateFrom != DateTime.MinValue)
                {
                    searchCriterias.Add(SearchCriteria.DateFrom, dateFrom);
                }
                if (dateTo != DateTime.MinValue)
                {
                    searchCriterias.Add(SearchCriteria.DateTo, dateTo);
                }
                else if (CommonUIHelper.IsCurrentlyProcessing())
                {
                    MessageBox.Show("A process is already running, please wait and retry later.");
                    return;
                }
                #endregion

                filterErrorMessage.Visibility = System.Windows.Visibility.Hidden;
                SearchHelper searchHelper = new SearchHelper(searchCriterias);

                CommonUIHelper.LaunchChangesetAnalysis(searchHelper
                    , labelPattern
                    , ProcessCheckbox(chkShowFiles)
                    , ProcessCheckbox(chkGroupFiles)
                    , ProcessCheckbox(chkShowLabels)
                    , ProcessCheckbox(chkShowComments)
                    , ProcessCheckbox(chkShowWI)
                    , SelectedTeamProjectName
                    , txtOutput.Text
                    , _selectedFiles
                    , this._queryResults
                    , _selectedLinks
                    , groupByFieldName);
            }
            catch (TeamFoundationServiceUnavailableException ex)
            {
                MessageBox.Show(ex.Message, "Please check your connection to TFS.");
            }
            catch (UnauthorizedAccessException ex)
            {
                MessageBox.Show(ex.Message, "Unauthorized Access Exception");
            }
            finally
            {
                Mouse.OverrideCursor = null;
            }
        }

        /// <summary>
        /// Indicates whether or not the checkbox is checked
        /// </summary>
        /// <param name="box">The checkbox to process</param>
        /// <returns>True if it is checked or false if it is not</returns>
        private bool ProcessCheckbox(CheckBox box)
        {
            if ((box.IsChecked != null) && (box.IsChecked == true))
                return true;
            else
                return false;
        }

        /// <summary>
        /// Launch the option editor dialog
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnOptions_Click(object sender, RoutedEventArgs e)
        {
            Options o = new Options();
            o.ShowDialog();
        }

        private void RemoveFile(object sender, RoutedEventArgs e)
        {
            Button button = (Button)sender;

            string fileToRemove = (string)button.Tag;
            RemoveSelectedFile(fileToRemove);
        }

        private void RemoveItem_Click(object sender, RoutedEventArgs e)
        {
            List<FileChangeInfo> filesToRemove = new List<FileChangeInfo>();

            foreach (FileChangeInfo file in _selectedFiles.FindAll(delegate(FileChangeInfo f) { return f.Checked; }))
            {
                filesToRemove.Add(file);
            }
            foreach (FileChangeInfo file in filesToRemove)
            {
                RemoveSelectedFile(file.FullPath);
            }
        }

        private void SwitchFiles(bool valueToSet)
        {
            for (int i = 0; i < _selectedFiles.Count; i++)
            {
                if (_selectedFiles[i].Checked)
                {
                    _selectedFiles[i].Selected = valueToSet;
                }
            }
            lstSelectedFiles.ItemsSource = null;
            lstSelectedFiles.ItemsSource = _selectedFiles;
        }

        private void SelectItem_Click(object sender, RoutedEventArgs e)
        {
            SwitchFiles(true);
        }

        private void UnselectItem_Click(object sender, RoutedEventArgs e)
        {
            SwitchFiles(false);
        }

        private void chkShowFiles_Checked(object sender, RoutedEventArgs e)
        {
            chkGroupFiles.IsEnabled = true;
        }

        private void chkShowFiles_Unchecked(object sender, RoutedEventArgs e)
        {
            chkGroupFiles.IsChecked = false;
            chkGroupFiles.IsEnabled = false;
        }

        private void CheckAll(object sender, RoutedEventArgs e)
        {
            ResetAll(true);
        }

        private void UncheckAll(object sender, RoutedEventArgs e)
        {
            ResetAll(false);
        }

        private void ResetAll(bool value)
        {
            foreach (BranchData branch in _branches)
            {
                branch.Selected = value;
            }

            lstResults.ItemsSource = null;
            lstResults.ItemsSource = _branches;
        }

        private void AddItem_Click(object sender, RoutedEventArgs e)
        {
            AddFile a = new AddFile();
            a.Left = SystemParameters.PrimaryScreenWidth / 2 - a.Width / 2;
            a.Top = SystemParameters.PrimaryScreenHeight / 2 - a.Height / 2;
            a.ShowDialog();
        }

        private void EditItem_Click(object sender, RoutedEventArgs e)
        {
            AddFile a = new AddFile(_selectedFiles.FindAll(delegate(FileChangeInfo f) { return f.Checked; })[0].FullPath);
            a.Left = SystemParameters.PrimaryScreenWidth / 2 - a.Width / 2;
            a.Top = SystemParameters.PrimaryScreenHeight / 2 - a.Height / 2;
            a.ShowDialog();
        }

        private void rbSearchByFile_Checked(object sender, RoutedEventArgs e)
        {
            if (this._branches != null && this._branches.Count > 0)
            {
                IsInSearchByFile = true;
                SetToolbarButtons();

                int changesetID;

                try
                {
                    if (txbChangesetID.Text.Length > 0)
                    {
                        if (!int.TryParse(txbChangesetID.Text, out changesetID))
                        {
                            txbChangesetIDErrorMessage.Visibility = Visibility.Visible;
                            return;
                        }

                        lstSelectedFiles.ItemsSource = null;
                        _selectedFiles = CommonUIHelper.GetFilesByChangesetID(changesetID);
                        lstSelectedFiles.ItemsSource = _selectedFiles;
                    }
                }
                catch (ChangesetNotFoundException)
                {
                    txbChangesetIDErrorMessage.Visibility = Visibility.Visible;
                }
                catch
                {
                    if (CommonUIHelper.Helper._wis != null)
                    {
                        txbChangesetIDErrorMessage.Visibility = Visibility.Visible;
                    }
                }
            }
        }

        private void rbSearchByChangesetID_Checked(object sender, RoutedEventArgs e)
        {
            IsInSearchByFile = false;
            SetToolbarButtons();
        }

        private void SetToolbarButtons()
        {
            BtnAddItem.IsEnabled = IsInSearchByFile;
            BtnEditItem.IsEnabled = IsInSearchByFile;
            BtnSelectAllItems.IsEnabled = IsInSearchByFile;
            BtnRemoveItem.IsEnabled = IsInSearchByFile;
            BtnSelectItem.IsEnabled = IsInSearchByFile;
            BtnUnselectItem.IsEnabled = IsInSearchByFile;
            lstSelectedFiles.IsEnabled = IsInSearchByFile;
            txbChangesetID.IsEnabled = !IsInSearchByFile;
            btnLoadBranches.IsEnabled = !IsInSearchByFile;
        }

        private void btnLoadBranches_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                TFSSelection s = new TFSSelection();
                s.Left = SystemParameters.PrimaryScreenWidth / 2 - s.Width / 2;
                s.Top = SystemParameters.PrimaryScreenHeight / 2 - s.Height / 2;
                s.ShowDialog();

                if (s.TeamProject != null)
                {
                    SelectedTeamProjectName = s.TeamProject.Name;
                    LoadProject();
                }
            }
            catch (TeamFoundationServiceUnavailableException ex)
            {
                MessageBox.Show(ex.Message, "Please check your connection to TFS.");
            }
        }

        private void chkShowLabels_Checked(object sender, RoutedEventArgs e)
        {
            txbLabelPattern.IsEnabled = true;
        }

        private void chkShowLabels_Unchecked(object sender, RoutedEventArgs e)
        {
            txbLabelPattern.IsEnabled = false;
        }

        private void SelectAllItems_Click(object sender, RoutedEventArgs e)
        {
            lstSelectedFiles.ItemsSource = null;
            if (_selectedFiles.Find(x => !x.Checked) != null)
            {
                _selectedFiles.ForEach(x => x.Checked = true);
            }
            else
            {
                _selectedFiles.ForEach(x => x.Checked = false);
            }
            lstSelectedFiles.ItemsSource = _selectedFiles;
        }
        #endregion
    }
}
